﻿' ----------------------------------------------------------------------------------
' Microsoft Developer & Platform Evangelism
' 
' Copyright (c) Microsoft Corporation. All rights reserved.
' 
' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ----------------------------------------------------------------------------------
' The example companies, organizations, products, domain names,
' e-mail addresses, logos, people, places, and events depicted
' herein are fictitious.  No association with any real company,
' organization, product, domain name, email address, logo, person,
' places, or events is intended or should be inferred.
' ----------------------------------------------------------------------------------

Imports Microsoft.Samples.WindowsPhoneCloud.StorageClient.Exceptions
Imports System.Text
Imports System.Runtime.Serialization
Imports System.Net.Browser
Imports System.Net
Imports System.IO
Imports System.Globalization

Namespace Credentials

    Public Class RegistrationClient
        Implements IRegistrationClient
        Private Const RegisterSignatureOperation As String = "/register"
        Private Const ValidateSignatureOperation As String = "/validate"

        Private ReadOnly storageCredentials As IStorageCredentials

        Private ReadOnly serviceUri As String

        Private clientHttpValue As IWebRequestCreate

        Public Sub New(ByVal serviceUri As String, ByVal storageCredentials As IStorageCredentials)
            Me.serviceUri = serviceUri
            Me.storageCredentials = storageCredentials
        End Sub

        Friend Property ClientHttp() As IWebRequestCreate
            Get
                Return If(Me.clientHttpValue IsNot Nothing, Me.clientHttpValue, WebRequestCreator.ClientHttp)
            End Get

            Set(ByVal value As IWebRequestCreate)
                Me.clientHttpValue = value
            End Set
        End Property

        Public Sub CheckUserRegistration(ByVal registeredCallback As Action(Of RegistrationSuccessArgs), ByVal notRegisteredCallback As Action(Of RegistrationSuccessArgs), ByVal exceptionCallback As Action(Of RegistrationExceptionArgs)) Implements IRegistrationClient.CheckUserRegistration
            Dim uriBuilder = New UriBuilder(Me.serviceUri)
            uriBuilder.Path &= ValidateSignatureOperation
            ' adding an incremental seed to avoid a cached response.
            uriBuilder.Query &= String.Format(CultureInfo.InvariantCulture, "incrementalSeed={0}", Date.UtcNow.Ticks)

            Dim request = Me.ClientHttp.Create(uriBuilder.Uri)
            request.Method = "GET"

            Me.storageCredentials.SignRequest(request, -1)

            request.BeginGetResponse(Sub(asyncResult)
                                         Try
                                             Dim response = request.EndGetResponse(asyncResult)
                                             Dim reader = New StreamReader(response.GetResponseStream())
                                             Dim serializer = New DataContractSerializer(GetType(String))
                                             Dim responseBody = TryCast(serializer.ReadObject(response.GetResponseStream()), String)
                                             reader.Close()
                                             Dim registered As Boolean
                                             If Boolean.TryParse(responseBody, registered) AndAlso registered Then
                                                 registeredCallback(New RegistrationSuccessArgs())
                                             Else
                                                 notRegisteredCallback(New RegistrationSuccessArgs())
                                             End If
                                         Catch exception As Exception
                                             Dim webException = TryCast(exception, WebException)
                                             If webException IsNot Nothing Then
                                                 exceptionCallback(New RegistrationExceptionArgs With {.Exception = StorageClientExceptionParser.ParseHttpWebException(webException), .IsError = True})
                                             Else
                                                 exceptionCallback(New RegistrationExceptionArgs With {.Exception = New HttpWebException(exception.GetBaseException().Message), .IsError = True})
                                             End If
                                         End Try
                                     End Sub, Nothing)
        End Sub

        Public Sub Register(ByVal userName As String, ByVal email As String, ByVal successCallback As Action(Of RegistrationSuccessArgs), ByVal exceptionCallback As Action(Of RegistrationExceptionArgs)) Implements IRegistrationClient.Register
            If String.IsNullOrEmpty(userName) OrElse String.IsNullOrEmpty(email) Then
                Return
            End If

            Dim uriBuilder = New UriBuilder(Me.serviceUri)
            uriBuilder.Path &= RegisterSignatureOperation

            Dim request = Me.ClientHttp.Create(uriBuilder.Uri)
            request.Method = "POST"
            request.ContentType = "text/xml"

            Dim data = New RegistrationUser With {.Name = userName, .EMail = email}
            Dim postData = String.Empty

            Using stream = New MemoryStream()
                Dim serializer = New DataContractSerializer(GetType(RegistrationUser))
                serializer.WriteObject(stream, data)
                Dim contextAsByteArray() As Byte = stream.ToArray()
                postData = Encoding.UTF8.GetString(contextAsByteArray, 0, contextAsByteArray.Length)
            End Using

            Me.storageCredentials.SignRequest(request, postData.Length)

            request.BeginGetRequestStream(Sub(ar)
                                              Dim postStream = request.EndGetRequestStream(ar)
                                              Dim byteArray = Encoding.UTF8.GetBytes(postData)
                                              postStream.Write(byteArray, 0, postData.Length)
                                              postStream.Close()
                                              request.BeginGetResponse(Sub(asyncResult)
                                                                           Dim status = String.Empty
                                                                           Try
                                                                               Dim response = request.EndGetResponse(asyncResult)
                                                                               Dim serializer = New DataContractSerializer(GetType(String))
                                                                               status = TryCast(serializer.ReadObject(response.GetResponseStream()), String)
                                                                               If String.IsNullOrEmpty(status) OrElse (Not status.Equals("Success", StringComparison.OrdinalIgnoreCase)) Then
                                                                                   exceptionCallback(New RegistrationExceptionArgs() With {.IsError = False, .Exception = New HttpWebException(status)})
                                                                               Else
                                                                                   successCallback(New RegistrationSuccessArgs() With {.UserName = userName})
                                                                               End If
                                                                           Catch exception As Exception
                                                                               Dim webException = TryCast(exception, WebException)
                                                                               If webException IsNot Nothing Then
                                                                                   exceptionCallback(New RegistrationExceptionArgs() With {.IsError = True, .Exception = StorageClientExceptionParser.ParseHttpWebException(webException)})
                                                                               Else
                                                                                   exceptionCallback(New RegistrationExceptionArgs() With {.IsError = True, .Exception = New HttpWebException(exception.GetBaseException().Message)})
                                                                               End If
                                                                           End Try
                                                                       End Sub, Nothing)
                                          End Sub, request)
        End Sub
    End Class
End Namespace